#ifndef __SUBSYSTEM_ANIMAL_ENTITIES_H__
#define __SUBSYSTEM_ANIMAL_ENTITIES_H__

#include <vector>
#include <map>
#include <set>
#include <list>
#include <functional>

#include "Subsystem.hpp"
#include "entt/entt.hpp"
#include "nlohmann/json.hpp"
#include "blockingconcurrentqueue.h"
#include "GameLock.hpp"

#include "Engine/Point2.hpp"
#include "Engine/Point3.hpp"
#include "Engine/Vector3.hpp"
#include "Engine/GameGuid.h"


using namespace PocketSurvival::Engine;

namespace PocketSurvival
{
    struct AnimalEntityData
    {
        std::string entityName;
        Vector3 position;
    };

    class SubsystemTimeOfDay;
    class SubsystemTerrain;

    class SubsystemAnimalEntities : public Subsystem
    {
    public:
        SubsystemAnimalEntities();

        virtual void onTerrainChunkAdded(TerrainChunk *terrainChunk);
        virtual void onTerrainChunkRemoved(TerrainChunk *terrainChunk);

        virtual void update(float dt) override;
        virtual void load(const nlohmann::json& json) override;
        virtual void save(nlohmann::json& json) override;

        virtual const std::string& getName() const override;
        virtual SubLoadEchelon getLoadEchelon() override;
        virtual SubUpdateType getUpdateType() override;

    public:
        void addAnimalEntity(const std::string &entityName, const Vector3 &position);
        void removeAnimalEntity(entt::entity entity);

        // 必须先对 animalLock 加锁后才能使用该函数，等动物数据处理完后再进行解锁处理，解锁完后返回的 set 对象不可再使用了
        inline const std::set<entt::entity> &getAnimalEntitySet();

    protected:
        void createAnimalEntity(const nlohmann::json& jsonData);
        void internalSave();

    public:
        Recursive_SpinLock animalLock;

    protected:
        std::set<entt::entity> m_animalEntitiesSet;        

        std::set<entt::entity> m_removeAnimalSetCatch;
        std::set<entt::entity> m_removeAnimalSet;
        std::mutex m_removeAnimalSetMutex;

        moodycamel::BlockingConcurrentQueue<AnimalEntityData *> m_addAnimalQueue;

        std::map<Point2, std::vector<AnimalEntityData*>> m_chunkAnimalsMap;     // 没有加载的区块中有哪些动物
        std::recursive_mutex m_chunkAnimalMapkMutex;

        SubsystemTimeOfDay *m_subsystemTimeOfDay;
        SubsystemTerrain *m_subsystemTerrain;
    };

    inline SubsystemAnimalEntities::SubsystemAnimalEntities() {}
    inline const std::set<entt::entity> &SubsystemAnimalEntities::getAnimalEntitySet()
    {
        return m_animalEntitiesSet;
    }
}

#endif